﻿using Singer.BackgroundJob.RabbitMQ.BackgroundJobLogs.Dtos;
using Singer.BackgroundJob.RabbitMQ.Contracts;
using Singer.BackgroundJob.RabbitMQ.Contracts.BackgroundJobLogs;
using Singer.Core;
using System.Diagnostics.CodeAnalysis;

namespace Singer.BackgroundJob.RabbitMQ.BackgroundJobLogs;

/// <summary>
/// 后台任务日志 领域服务
/// </summary>
public class BackgroundJobLogManager
{
    private readonly BackgroundJobConsumerCollection _consumers;
    private readonly IBackgroundJobLogRepository _backgroundJobLogRepository;
    private readonly IBackgroundJobLogDetailRepository _backgroundJobLogDetailRepository;
    public BackgroundJobLogManager(
        BackgroundJobConsumerCollection consumers,
        IBackgroundJobLogDetailRepository backgroundJobLogDetailRepository,
        IBackgroundJobLogRepository backgroundJobLogRepository)
    {
        _consumers = consumers;
        _backgroundJobLogDetailRepository = backgroundJobLogDetailRepository;
        _backgroundJobLogRepository = backgroundJobLogRepository;
    }

    /// <summary>
    /// 新增任务日志
    /// </summary>
    /// <param name="args">任务参数</param>
    public async Task<BackgroundJobLog> CreateAsync<TArgs>([NotNull] TArgs args) where TArgs : IBackgroundJobArgs
    {
        var consumer = _consumers.FirstOrDefault(x => x.ArgsType == typeof(TArgs));
        if (consumer == null)
            throw new Exception("未找到该任务类型对应的后台任务消费者");
        var jobLog = new BackgroundJobLog(consumer, args);
        await _backgroundJobLogRepository.InsertAsync(jobLog);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = jobLog.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Info,
            CreateTime = Cores.BeiJingNow,
            Content = "任务创建完成，已入队列"
        });
        return jobLog;
    }

    /// <summary>
    /// 获取任务
    /// </summary> 
    public async Task<BackgroundJobLog> GetAsync(string id)
    {
        var log = await _backgroundJobLogRepository.GetAsync(x => x.Id == id);
        if (log == null)
            throw new Exception("任务不存在");
        return log;
    }

    /// <summary>
    /// 初始化
    /// </summary>
    public async Task InitAsync(BackgroundJobLog log)
    {
        log.Init();
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Info,
            CreateTime = Cores.BeiJingNow,
            Content = "任务已出队列，开始解析"
        });
    }

    /// <summary>
    /// 任务开始运行
    /// </summary>
    public async Task RunningAsync(BackgroundJobLog log)
    {
        log.Running();
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Info,
            CreateTime = Cores.BeiJingNow,
            Content = "任务开始运行"
        });
    }

    /// <summary>
    /// 任务执行成功
    /// </summary>
    public async Task SuccessAsync(BackgroundJobLog log)
    {
        log.Success();
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Info,
            CreateTime = Cores.BeiJingNow,
            Content = "任务执行完成"
        });
    }

    /// <summary>
    /// 任务执行失败
    /// </summary>
    /// <returns>失败后，是否回到队列重试</returns>
    public async Task<bool> FailAsync(BackgroundJobLog log, string message)
    {
        bool retry = log.Fail(message);
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Error,
            CreateTime = Cores.BeiJingNow,
            Content = $"任务执行失败：{message}。【{(retry ? "即将返回队列，自动重启" : "任务终止")}】"
        });
        return retry;
    }

    /// <summary>
    /// 手动取消任务
    /// </summary>
    public async Task CancellingAsync(BackgroundJobLog log)
    {
        if (!log.Cancelling())
            throw new Exception("当前任务状态不可取消");
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Warning,
            CreateTime = Cores.BeiJingNow,
            Content = "任务取消中"
        });
    }

    /// <summary>
    /// 任务已取消
    /// </summary>
    public async Task CancelledAsync(BackgroundJobLog log)
    {
        log.Canceled();
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Warning,
            CreateTime = Cores.BeiJingNow,
            Content = "任务已取消"
        });
    }

    /// <summary>
    /// 手动重启任务
    /// </summary>
    public async Task ReStartingAsync(BackgroundJobLog log)
    {
        if (!log.ReStarting())
            throw new Exception("当前任务状态不可重启");
        await _backgroundJobLogRepository.UpdateAsync(log);
        await AddLogDetailAsync(new BackgroundJobLogDetailDto
        {
            LogId = log.Id,
            IsSystem = true,
            LogType = BackgroundJobLogType.Warning,
            CreateTime = Cores.BeiJingNow,
            Content = "任务手动重启，已入队列"
        });
    }

    #region LogDetail 日志详情
    /// <summary>
    /// 新增后台任务日志详情
    /// </summary>
    /// <param name="logDto">日志详情</param>
    public Task AddLogDetailAsync(BackgroundJobLogDetailDto logDto)
    {
        var logDetail = new BackgroundJobLogDetail(logDto);
        return _backgroundJobLogDetailRepository.InsertAsync(logDetail);
    }

    /// <summary>
    /// 批量新增后台任务日志详情
    /// </summary>
    /// <param name="logDtos">日志详情列表</param>
    public Task AddLogDetailAsync(List<BackgroundJobLogDetailDto> logDtos)
    {
        List<BackgroundJobLogDetail> logDetails = new List<BackgroundJobLogDetail>();
        foreach (var logDto in logDtos)
        {
            var logDetail = new BackgroundJobLogDetail(logDto);
            logDetails.Add(logDetail);
        }
        return _backgroundJobLogDetailRepository.InsertAsync(logDetails);
    }
    #endregion
}
